package com.example.gobang.model;


import com.example.gobang.SpringGobangApplication;
import com.example.gobang.constant.Constants;
import com.example.gobang.manager.OnlineUserManager;
import com.example.gobang.manager.RoomManger;
import com.example.gobang.mapper.UserMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import javax.swing.plaf.ToolBarUI;
import java.io.IOException;
import java.util.UUID;

@Slf4j
public class Room {
    private String roomId;
    private UserInfo user1;
    private UserInfo user2;
    private int whiteUser;
    private int piecesNumber = 0;
    // 棋盘信息
    private int[][] board = new int[Constants.CHESSBOARD_MAX_ROW][Constants.CHESSBOARD_MAX_COL];

    public int getWhiteUser() {
        return whiteUser;
    }

    public void setWhiteUser(int whiteUser) {
        this.whiteUser = whiteUser;
    }

    public Room() {
        // 构造 Room 时生成唯一字符串表示房间id
        roomId = UUID.randomUUID().toString().replace("-", "");
        onlineUserManager = SpringGobangApplication.context.getBean(OnlineUserManager.class);
        roomManger = SpringGobangApplication.context.getBean(RoomManger.class);
        objectMapper = SpringGobangApplication.context.getBean(ObjectMapper.class);
        userMapper = SpringGobangApplication.context.getBean(UserMapper.class);
    }

    // 引入 OnlineUserManager
    private ObjectMapper objectMapper;
    private OnlineUserManager onlineUserManager;
    private RoomManger roomManger;
    private UserMapper userMapper;
    public void putChess(String payload) throws IOException {
        // 1. 获取落子信息
        GameRequest request = objectMapper.readValue(payload, GameRequest.class);
        GameResult resp = new GameResult();
        // 判断这个子是玩家1落的，还是玩家2落的
        int chess = request.getUserId() == user1.getUserId() ? 1 : 2;
        // 落子位置
        int row = request.getRow();
        int col = request.getCol();
        // 判断是否重复落子
        if(board[row][col] != 0) {
            log.info("当前位置 row:{}, col:{}已有棋子", row, col);
            return;
        }
        // 落子
        board[row][col] = chess;
        // 打印棋盘，观察落子情况
        printBoard(board);
        // 2. 进行胜负判定
        int winner = checkWinner(row, col, chess);
        // 3. 返回响应
        resp.setRow(row);
        resp.setCol(col);
        resp.setWinner(winner);
        resp.setUserId(request.getUserId());
        // 发送数据
        WebSocketSession session1 = onlineUserManager.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getFromGameRoom(user2.getUserId());
        // 若 玩家1 已下线，则 玩家2 获胜
        if(session1 == null) {
            resp.setWinner(user2.getUserId());
            log.info("玩家1：{}掉线", user1.getUserName());
        }
        if(session2 == null) {
            resp.setWinner(user1.getUserId());
            log.info("玩家2:{}掉线", user2.getUserName());
        }
        // 构造响应，并通过session 传输
        Result result = new Result();
        result.setStatus(Constants.PUT_CHESS);
        result.setData(resp);
        result.setErrorMessage("");
        String respJson = objectMapper.writeValueAsString(result);
        session1.sendMessage(new TextMessage(respJson));
        session2.sendMessage(new TextMessage(respJson));
        // 若胜负已分，则可以直接销毁房间
        if(resp.getWinner() != 0) {
            log.info("游戏结束！房间{}即将销毁！获胜方为{}", roomId, winner);
            // 更新分数
            int winUserId = winner;
            int loseUserId = winner == user1.getUserId() ? user2.getUserId() : user1.getUserId();
            userMapper.userWin(winUserId);
            userMapper.userLose(loseUserId);
            // 销毁房间
            roomManger.remove(roomId, user1.getUserId(), user2.getUserId());
        }
    }

    private void printBoard(int[][] board) {
        log.info("打印棋盘，roodId:{}", roomId);
        System.out.println("***************************************************");
        for (int r = 0; r < Constants.CHESSBOARD_MAX_ROW; r++) {
            for (int c = 0; c < Constants.CHESSBOARD_MAX_COL; c++) {
                System.out.printf(board[r][c] + " ");
            }
            System.out.println();
        }
        System.out.println("***************************************************");
    }

    /**
     * 判定胜负
     * @param row
     * @param col
     * @return 0：尚未决出胜负 user1.getUserId：玩家1胜利 user2.getUserId：玩家2胜利 -1：平局
     */
    private int checkWinner(int row, int col, int chess) {
        piecesNumber++;
        // 判定是否是平局
        if(piecesNumber == Constants.CHESSBOARD_MAX_COL * Constants.CHESSBOARD_MAX_ROW) {
            return -1;
        }
        // 判定水平方向
        for (int c = col - 4; c <= col; c++) {
            try {
                if(board[row][c] == chess
                        && board[row][c + 1] == chess
                        && board[row][c + 2] == chess
                        && board[row][c + 3] == chess
                        && board[row][c + 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e) {
                // 数组越界，直接忽略，继续判定
                continue;
            }
        }
        // 判定垂直方向
        for (int r = row - 4; r <= row; r++) {
            try {
                if(board[r][col] == chess
                        && board[r + 1][col] == chess
                        && board[r + 2][col] == chess
                        && board[r + 3][col] == chess
                        && board[r + 4][col] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }
        // 判定左对角线
        for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++) {
            try {
                if(board[r][c] == chess
                        && board[r + 1][c + 1] == chess
                        && board[r + 2][c + 2] == chess
                        && board[r + 3][c + 3] == chess
                        && board[r + 4][c + 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }
        // 判定右对角线
        for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--) {
            try {
                if(board[r][c] == chess
                        && board[r + 1][c - 1] == chess
                        && board[r + 2][c - 2] == chess
                        && board[r + 3][c - 3] == chess
                        && board[r + 4][c - 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }
        return 0;
    }


    public String getRoomId() {
        return roomId;
    }

    public void setRoomId(String roomId) {
        this.roomId = roomId;
    }

    public UserInfo getUser1() {
        return user1;
    }

    public void setUser1(UserInfo user1) {
        this.user1 = user1;
    }

    public UserInfo getUser2() {
        return user2;
    }

    public void setUser2(UserInfo user2) {
        this.user2 = user2;
    }
}
